#include <jni.h>
#include <android/log.h>
#include <pthread.h>

#define WITH_THREAD 1
#define JNI_VERSION JNI_VERSION_1_6
#define LOG_TAG "zyf.test"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

static pthread_key_t _threadKey;
static JavaVM*       _javaVM = NULL;

extern "C" {

static JNIEnv* getEnv() {
    JNIEnv* env = (JNIEnv*)pthread_getspecific(_threadKey);
    if (!env) {
        // 缓冲env
        jint ret = _javaVM->GetEnv((void**)&env, JNI_VERSION);

        switch (ret) {
            case JNI_OK:
                break;
            case JNI_EDETACHED:
                if (_javaVM->AttachCurrentThread(&env, NULL) != JNI_OK) {
                    LOGI("缓冲 env 时attach thread 失败\n");
                }
                break;
            default:
                LOGI("获取 env 失败了\n");
                break;
        }
        pthread_setspecific(_threadKey, env);
    }
    return env;
}

static void onJniThreadDestroyed(void* value) {
    // 线程被销毁的时候，将它和Java VM断开链接
    if (value) {
        // 这里可以演示一个重复Detach的错误
        if (_javaVM->GetEnv(&value, JNI_VERSION) != JNI_EDETACHED) {
            _javaVM->DetachCurrentThread();
        }
    }
    pthread_setspecific(_threadKey, NULL);
}

jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    _javaVM = vm;
    if (pthread_key_create(&_threadKey, onJniThreadDestroyed) != 0) {
        LOGI("In %s 创建 thread key 失败\n", __func__);
        return -1;
    }

    return JNI_VERSION;
}

void JNI_OnUnload(JavaVM *vm, void *reserved) {
    _javaVM = NULL;
    pthread_key_delete(_threadKey);
}

static void hello_java(JNIEnv* env) {
    LOGI("In C current thread id [%ld]. Now try to call hello() in Java\n", pthread_self());
    jclass cls = env->FindClass("zyf/test/MainActivity");
    if (cls) {
        jmethodID mid = env->GetStaticMethodID(cls, "hello", "()V");
        if (mid) {
            env->CallStaticVoidMethod(cls, mid);
        }
        env->DeleteLocalRef(cls);
    }
}

static void* thread_func(void* arg) {
#ifdef WITH_THREAD
    hello_java(getEnv());
#else
    hello_java((JNIEnv*)arg);
#endif
    return NULL;
}

JNIEXPORT void JNICALL Java_zyf_test_MainActivity_startC(JNIEnv* env, jobject obj) {
    hello_java(env);
    pthread_t tid;
    if (pthread_create(&tid, NULL, thread_func, env) != 0) {
        LOGI("error: 创建线程失败");
    }
}

}
